import os
import sys
import argparse
import logging
import threading
from flask import Flask, send_file, abort

def get_image_filepath(device: str, filename: str) -> str:
    """获取设备截图的完整路径，用于HTTP服务器访问"""
    # 获取配置的图片目录
    images_dir = os.environ.get('IMAGES_DIR', os.path.abspath('./images'))
    return os.path.join(images_dir, device, filename)

def daemonize():
    # Daemonize the process
    try:
        pid = os.fork()
        if pid > 0:
            # exit first parent
            sys.exit(0)
    except OSError as e:
        sys.stderr.write(f"fork #1 failed: {e.errno} ({e.strerror})\n")
        sys.exit(1)

    os.chdir("/")
    os.setsid()
    os.umask(0)

    try:
        pid = os.fork()
        if pid > 0:
            # exit second parent
            sys.exit(0)
    except OSError as e:
        sys.stderr.write(f"fork #2 failed: {e.errno} ({e.strerror})\n")
        sys.exit(1)

    # redirect standard file descriptors
    sys.stdout.flush()
    sys.stderr.flush()
    # It's good practice to use a log file for daemons, but for simplicity, we'll use /dev/null
    # For actual logging, replace os.devnull with a log file path
    # For example: log_file = "/tmp/daemon_proxy.log"
    # so = open(log_file, 'a+')
    # se = open(log_file, 'a+')
    si = open(os.devnull, 'r')
    so = open(os.devnull, 'a+')
    se = open(os.devnull, 'a+')

    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())


def start_http_server(host: str, port: int):
    app = Flask(__name__)
    
    # 定义资源目录，可以通过环境变量或配置文件进行配置
    IMAGES_DIR = os.environ.get('IMAGES_DIR', os.path.abspath('./images'))
    LOGS_DIR = os.environ.get('LOGS_DIR', os.path.abspath('./logs'))
    STATIC_DIR = os.environ.get('STATIC_DIR', os.path.abspath('./static'))
    
    # 确保资源目录存在
    os.makedirs(IMAGES_DIR, exist_ok=True)
    os.makedirs(LOGS_DIR, exist_ok=True)
    os.makedirs(STATIC_DIR, exist_ok=True)
    
    logging.info(f"Images directory: {IMAGES_DIR}")
    logging.info(f"Logs directory: {LOGS_DIR}")
    logging.info(f"Static directory: {STATIC_DIR}")
    
    # 错误处理
    @app.errorhandler(404)
    def not_found(error):
        return {"error": "Resource not found", "code": 404}, 404
    
    @app.errorhandler(403)
    def forbidden(error):
        return {"error": "Access forbidden", "code": 403}, 403
    
    @app.errorhandler(500)
    def server_error(error):
        return {"error": "Internal server error", "code": 500}, 500
    
    @app.route('/images/<path:filename>')
    def serve_image(filename):
        app.logger.debug(f"Serving image: {filename}")
        try:
            # 安全地构建文件路径，防止目录遍历攻击
            safe_filename = os.path.normpath(filename).lstrip('/')
            image_path = os.path.join(IMAGES_DIR, safe_filename)
            logging.debug(f"Serving image: {image_path}")
            # 验证文件路径是否在允许的目录内
            if not image_path.startswith(IMAGES_DIR):
                logging.warning(f"Attempted directory traversal: {filename}")
                abort(403)
                
            if os.path.exists(image_path) and os.path.isfile(image_path):
                # 根据文件扩展名确定MIME类型
                mimetype = 'image/png'  # 默认
                if image_path.lower().endswith('.jpg') or image_path.lower().endswith('.jpeg'):
                    mimetype = 'image/jpeg'
                elif image_path.lower().endswith('.gif'):
                    mimetype = 'image/gif'
                    
                return send_file(image_path, mimetype=mimetype)
            else:
                logging.error(f"Image file not found: {image_path}")
                abort(404)
        except Exception as e:
            logging.error(f"Error serving image: {str(e)}")
            abort(500)
    
    @app.route('/logs/<path:filename>')
    def serve_log(filename):
        try:
            # 安全地构建文件路径，防止目录遍历攻击
            safe_filename = os.path.normpath(filename).lstrip('/')
            log_path = os.path.join(LOGS_DIR, safe_filename)
            
            # 验证文件路径是否在允许的目录内
            if not log_path.startswith(LOGS_DIR):
                logging.warning(f"Attempted directory traversal: {filename}")
                abort(403)
                
            if os.path.exists(log_path) and os.path.isfile(log_path):
                return send_file(log_path, mimetype='text/plain')
            else:
                logging.error(f"Log file not found: {log_path}")
                abort(404)
        except Exception as e:
            logging.error(f"Error serving log: {str(e)}")
            abort(500)
    
    # 通用静态文件服务
    @app.route('/static/<path:filename>')
    def serve_static(filename):
        try:
            # 安全地构建文件路径，防止目录遍历攻击
            safe_filename = os.path.normpath(filename).lstrip('/')
            file_path = os.path.join(STATIC_DIR, safe_filename)
            
            # 验证文件路径是否在允许的目录内
            if not file_path.startswith(STATIC_DIR):
                logging.warning(f"Attempted directory traversal: {filename}")
                abort(403)
                
            if os.path.exists(file_path) and os.path.isfile(file_path):
                # 自动检测MIME类型
                return send_file(file_path)
            else:
                logging.error(f"Static file not found: {file_path}")
                abort(404)
        except Exception as e:
            logging.error(f"Error serving static file: {str(e)}")
            abort(500)
    
    # 添加健康检查端点
    @app.route('/health')
    def health_check():
        return {"status": "ok", "service": "device_proxy_http"}
    
    # 添加根路径响应
    @app.route('/')
    def index():
        return {"status": "running", "service": "SmartUI Device Proxy HTTP Server", 
                "endpoints": ["/images/", "/logs/", "/static/", "/health"]}
    
    logging.info(f"HTTP server starting on {host}:{port}...")
    app.run(host=host, port=port, debug=False, threaded=True)


def main():
    parser = argparse.ArgumentParser(description="HTTP Server for SmartUI")
    parser.add_argument('--daemon', action=argparse.BooleanOptionalAction, default=True, help='Run as daemon (default: True)')
    parser.add_argument('--host', type=str, default='0.0.0.0', help='HTTP server IP address to bind (default: 0.0.0.0)')
    parser.add_argument('--port', type=int, default=8080, help='HTTP server port to bind (default: 8080)')
    parser.add_argument('--log-file', type=str, default='http_server.log', help='Log file path (default: http_server.log)')
    parser.add_argument('--log-level', type=str, default='INFO', help='Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL (default: INFO)')
    parser.add_argument('--images-dir', type=str, default='./images', help='Images directory path (default: ./images)')
    parser.add_argument('--logs-dir', type=str, default='./logs', help='Logs directory path (default: ./logs)')
    parser.add_argument('--static-dir', type=str, default='./static', help='Static files directory path (default: ./static)')
    args = parser.parse_args()
    match args.log_level:
        case "DEBUG":
            logging_level = logging.DEBUG
        case "INFO":
            logging_level = logging.INFO
        case "WARNING":
            logging_level = logging.WARNING
        case "ERROR":
            logging_level = logging.ERROR
        case "CRITICAL":
            logging_level = logging.CRITICAL
        case _:
            logging_level = logging.INFO
    
    # 配置日志
    if args.daemon:
        daemonize()
        logging.basicConfig(
            level=logging_level,
            filename=args.log_file,    # 指定日志文件
            filemode='w',          # 文件写入模式，'w'覆盖，'a'追加
            format='%(asctime)s - %(levelname)s - %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S')
    else:
        logging.basicConfig(
            level=logging_level,
            format='%(asctime)s - %(levelname)s - %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S')
        
    # 设置环境变量，用于HTTP服务器
    os.environ['IMAGES_DIR'] = os.path.abspath(args.images_dir)
    os.environ['LOGS_DIR'] = os.path.dirname(os.path.abspath(args.log_file)) if args.log_file else os.path.abspath(args.logs_dir)
    os.environ['STATIC_DIR'] = os.path.abspath(args.static_dir)
    
    # 输出服务器信息
    logging.info(f"HTTP Server will listen on: {args.host}:{args.port}")
    logging.info(f"Log file: {os.path.abspath(args.log_file)}")
    logging.info(f"Log level: {args.log_level}")
    logging.info(f"Images directory: {os.environ['IMAGES_DIR']}")
    logging.info(f"Logs directory: {os.environ['LOGS_DIR']}")
    logging.info(f"Static directory: {os.environ['STATIC_DIR']}")

    # 启动HTTP服务器
    start_http_server(args.host, args.port)


if __name__ == "__main__":
    main()